using System;
using System.Reflection;

namespace Com.ContentRendering.Api.DataEngine.Handler.Child
{
    /// <summary/>
    internal class PropertyChildHandler : AbstractChildHandler
    {
        /// <summary/>
        internal PropertyChildHandler(
            ReflectionCache reflectionCache,
            object data,
            string name)
            : base(
            reflectionCache,
            data,
            name) {}

        /// <summary/>
        internal override object Invoke()
        {
            Type type = base._data.GetType();

            // does the property not exist
            if (base._reflectionCache.IsPropertyCached(type, base._name))
            {
                return base._successor.Invoke();
            }

            // fetch the property
            PropertyInfo propertyInfo = PropertyChildHandler.FetchProperty(
                type,
                base._name);

            // add the object to the cache ... doesn't matter if the property info is null
            base._reflectionCache.AddProperty(
                type,
                base._name,
                propertyInfo);

            // nothing to do if the property was not found
            if (propertyInfo == null)
            {
                return base._successor.Invoke();
            }

            // execute the property
            return propertyInfo.GetValue(
                this._data,
                new object[] {});
        }

        /// <summary/>
        private static PropertyInfo FetchProperty(
            Type type,
            string name)
        {
            // lets look at all of the properties for a match
            foreach (PropertyInfo propertyInfo in type.GetProperties())
            {
                // make sure the name matches
                if (propertyInfo.Name != name)
                {
                    continue;
                }

                // check the input and output parameters for a get property
                foreach (MethodInfo methodInfo in propertyInfo.GetAccessors())
                {
                    // get the parameters
                    ParameterInfo returnParameterInfo = methodInfo.ReturnParameter;
                    ParameterInfo[] parameterInfos = methodInfo.GetParameters();

                    // if the return parameter is void then its no a get parameter
                    if (returnParameterInfo.ParameterType == typeof(void))
                    {
                        continue;
                    }

                    // make sure the input parameters are not present
                    if (parameterInfos.Length != 0)
                    {
                        continue;
                    }

                    return propertyInfo;
                }
            }

            // the property was not found
            return null;
        }
    }
}
